#include "catalog.h"
#include "query.h"
#include "sort.h"
#include "index.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "utility.h"

Operator flipOp(Operator op)
{
    switch(op)
    {
        case LT:    op = GT;
                    break;
        case GT:    op = LT;
                    break;
        case LTE:   op = GTE;
                    break;
        case GTE:   op = LTE;
                    break;
        default:    op = op;
                    break;
    }
    return op;
}
// Simple nested loops
Status Operators::SNL(const string & result,          // output relation name
	              const int projCnt,              // number of attributes in the projection
                      const AttrDesc attrDescArray[], // The projection list (as AttrDesc)
                      const AttrDesc & attrDesc1,     // The left attribute in the join predicate
                      const Operator op,              // The join operation
                      const AttrDesc & attrDesc2,     // The left attribute in the join predicate
                      const int reclen)               // The lenght of a tuple in the result relation
{
    cout << "Algorithm: Simple NL Join" << endl;
    Status ret;

    HeapFileScan scan1(attrDesc1.relName, ret);
    if (ret != OK) return ret;
    HeapFileScan scan2(attrDesc2.relName, ret);
    if (ret != OK) return ret;

    HeapFile ansFile(result, ret);
    if (ret != OK) return ret;

    ret = scan1.startScan(0,0, (Datatype)0,0,(Operator)0);
    if (ret != OK) return ret;

    RID rid_out, rid_in;
    Record rec_out, rec_in;
    //get record
    //flip op
    //start second scan
    //get second rec
    while(scan1.scanNext(rid_out, rec_out) == OK)
    {
        if (ret != OK) return ret;
        Operator flip = flipOp(op);
        ret = scan2.startScan(attrDesc2.attrOffset, attrDesc1.attrLen, 
                (Datatype) attrDesc1.attrType,
                (char*) rec_out.data + attrDesc1.attrOffset, flip);
        while(scan2.scanNext(rid_in, rec_in) == OK)
        {
            //we have a match, must now make record and insert
            Record result;
            result.data = malloc(reclen);
            result.length = reclen;
            int recOffset = 0;
            for (int i = 0; i < projCnt; i++)
            {
                if (!strcmp(attrDescArray[i].relName, attrDesc1.relName))
                {
                    memcpy((char*)result.data + recOffset, 
                        (char*) rec_out.data + (attrDescArray[i].attrOffset),
                        attrDescArray[i].attrLen);
                }
                else 
                {
                    memcpy((char*)result.data + recOffset, 
                        (char*) rec_in.data + (attrDescArray[i].attrOffset),
                        attrDescArray[i].attrLen);
                }
                recOffset += attrDescArray[i].attrLen;
            }

            RID resultRID;
            ret = ansFile.insertRecord(result, resultRID);
            if (ret != OK) return ret;
            free(result.data);
        }
        ret = scan2.endScan();
        if (ret != OK) return ret;
    }
    ret = scan1.endScan();
    if (ret != OK) return ret;
    return OK;
}

